 /*******************************************************************************
  * Copyright (c) 2000, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  * Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font should be
  * activated and used by other components.
  *******************************************************************************/
 package org.eclipse.ui.internal.ide.dialogs;

 import java.lang.reflect.InvocationTargetException ;
 import java.util.ArrayList ;
 import java.util.Arrays ;
 import java.util.Hashtable ;
 import java.util.Iterator ;
 import java.util.List ;
 import java.util.Map ;

 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.dialogs.IDialogConstants;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.viewers.IContentProvider;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.wizard.IWizardContainer;
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.jface.wizard.WizardDialog;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.ICapabilityUninstallWizard;
 import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
 import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
 import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
 import org.eclipse.ui.internal.ide.registry.Capability;
 import org.eclipse.ui.internal.ide.registry.CapabilityRegistry;
 import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
 import org.eclipse.ui.model.WorkbenchContentProvider;

 /**
  * A property page for IProject resources to edit a single
  * capability at a time.
  */
 public class ProjectCapabilityEditingPropertyPage extends
         ProjectCapabilityPropertyPage {
     private static final int SIZING_WIZARD_WIDTH = 500;

     private static final int SIZING_WIZARD_HEIGHT = 500;

     private TableViewer table;

     private Button addButton;

     private Button removeButton;

     private ArrayList disabledCaps = new ArrayList ();

     private Capability selectedCap;

     private CapabilityRegistry reg;

     /**
      * Creates a new ProjectCapabilityEditingPropertyPage.
      */
     public ProjectCapabilityEditingPropertyPage() {
         super();
     }

     /* (non-Javadoc)
      * Method declared on PreferencePage
      */
     protected Control createContents(Composite parent) {
         Font font = parent.getFont();
         PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(),
                 IIDEHelpContextIds.PROJECT_CAPABILITY_PROPERTY_PAGE);
         noDefaultAndApplyButton();
         reg = IDEWorkbenchPlugin.getDefault().getCapabilityRegistry();

         Composite topComposite = new Composite(parent, SWT.NONE);
         GridLayout layout = new GridLayout();
         layout.marginHeight = 0;
         layout.marginWidth = 0;
         topComposite.setLayout(layout);
         topComposite.setLayoutData(new GridData(GridData.FILL_BOTH));

         String instructions;
         if (reg.hasCapabilities())
             instructions = IDEWorkbenchMessages.ProjectCapabilityPropertyPage_chooseCapabilities;
         else
             instructions = IDEWorkbenchMessages.ProjectCapabilityPropertyPage_noCapabilities;
         Label label = new Label(topComposite, SWT.LEFT);
         label.setFont(font);
         label.setText(instructions);

         Capability[] caps = reg.getProjectDisabledCapabilities(getProject());
         disabledCaps.addAll(Arrays.asList(caps));

         Composite mainComposite = new Composite(topComposite, SWT.NONE);
         layout = new GridLayout();
         layout.numColumns = 2;
         layout.marginHeight = 0;
         layout.marginWidth = 0;
         mainComposite.setLayout(layout);
         mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));

         Composite capComposite = new Composite(mainComposite, SWT.NONE);
         layout = new GridLayout();
         layout.marginHeight = 0;
         layout.marginWidth = 0;
         capComposite.setLayout(layout);
         capComposite.setLayoutData(new GridData(GridData.FILL_BOTH));

         label = new Label(capComposite, SWT.LEFT);
         label.setFont(font);
         label.setText(IDEWorkbenchMessages.ProjectCapabilitySelectionGroup_capabilities);

         table = new TableViewer(capComposite, SWT.SINGLE | SWT.H_SCROLL
                 | SWT.V_SCROLL | SWT.BORDER);
         table.getTable().setLayoutData(new GridData(GridData.FILL_BOTH));
         table.getTable().setFont(font);
         table.setLabelProvider(new CapabilityLabelProvider());
         table.setContentProvider(getContentProvider());
         table.setInput(getProject());

         Composite buttonComposite = new Composite(mainComposite, SWT.NONE);
         layout = new GridLayout();
         layout.marginHeight = 0;
         layout.marginWidth = 0;
         buttonComposite.setLayout(layout);
         buttonComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL));

         label = new Label(buttonComposite, SWT.LEFT);
         label.setFont(font);
         label.setText(""); //$NON-NLS-1$

         addButton = new Button(buttonComposite, SWT.PUSH);
         addButton.setText(IDEWorkbenchMessages.ProjectCapabilityEditingPropertyPage_add);
         addButton.setEnabled(true);
         addButton.addSelectionListener(new SelectionListener() {
             public void widgetSelected(SelectionEvent e) {
                 addCapability();
             }

             public void widgetDefaultSelected(SelectionEvent e) {
             }
         });
         GridData data = new GridData();
         data.horizontalAlignment = GridData.FILL;
         int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
         data.widthHint = Math.max(widthHint, addButton.computeSize(SWT.DEFAULT,
                 SWT.DEFAULT, true).x);
         addButton.setLayoutData(data);
         addButton.setFont(font);

         removeButton = new Button(buttonComposite, SWT.PUSH);
         removeButton.setText(IDEWorkbenchMessages.ProjectCapabilityEditingPropertyPage_remove);
         removeButton.setEnabled(false);
         removeButton.addSelectionListener(new SelectionListener() {
             public void widgetSelected(SelectionEvent e) {
                 removeCapability(selectedCap);
             }

             public void widgetDefaultSelected(SelectionEvent e) {
             }
         });
         data = new GridData();
         data.horizontalAlignment = GridData.FILL;
         widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
         data.widthHint = Math.max(widthHint, removeButton.computeSize(
                 SWT.DEFAULT, SWT.DEFAULT, true).x);
         removeButton.setLayoutData(data);
         removeButton.setFont(font);

         table.addSelectionChangedListener(new ISelectionChangedListener() {
             public void selectionChanged(SelectionChangedEvent event) {
                 selectedCap = null;
                 IStructuredSelection sel = (IStructuredSelection) event
                         .getSelection();
                 if (sel != null)
                     selectedCap = (Capability) sel.getFirstElement();
                 removeButton.setEnabled(selectedCap != null);
             }
         });

         return topComposite;
     }

     /**
      * Returns the content provider for the viewers
      */
     private IContentProvider getContentProvider() {
         return new WorkbenchContentProvider() {
             public Object [] getChildren(Object parentElement) {
                 if (parentElement instanceof IProject)
                     return reg.getProjectCapabilities((IProject) parentElement);
                 else
                     return null;
             }
         };
     }

     /**
      * Returns whether the category is considered disabled
      */
     private boolean isDisabledCapability(Capability cap) {
         return disabledCaps.contains(cap);
     }

     private void addCapability() {
         ProjectCapabilitySimpleAddWizard wizard;
         wizard = new ProjectCapabilitySimpleAddWizard(
                 PlatformUI.getWorkbench(), StructuredSelection.EMPTY,
                 getProject());
         WizardDialog dialog = new WizardDialog(getShell(), wizard);
         dialog.create();
         dialog.getShell().setSize(
                 Math.max(SIZING_WIZARD_WIDTH, dialog.getShell().getSize().x),
                 SIZING_WIZARD_HEIGHT);
         PlatformUI.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
                 IIDEHelpContextIds.UPDATE_CAPABILITY_WIZARD);
         dialog.open();

         table.refresh();
     }

     private void removeCapability(Capability cap) {
         ArrayList results = new ArrayList ();
         results.addAll(Arrays.asList(reg.getProjectCapabilities(getProject())));
         results.remove(cap);
         Capability[] caps = new Capability[results.size()];
         results.toArray(caps);

         for (int i = 0; i < caps.length; i++) {
             List prereqs = Arrays.asList(reg.getPrerequisiteIds(caps[i]));
             if (prereqs.contains(cap.getId())) {
                 MessageDialog
                         .openWarning(
                                 getShell(),
                                 IDEWorkbenchMessages.ProjectCapabilityPropertyPage_errorTitle,
                                 NLS.bind(IDEWorkbenchMessages.ProjectCapabilityPropertyPage_capabilityRequired, caps[i].getName()));
                 return;
             }
         }

         IStatus status = reg.validateCapabilities(caps);
         if (!status.isOK()) {
             ErrorDialog
                     .openError(
                             getShell(),
                             IDEWorkbenchMessages.ProjectCapabilityPropertyPage_errorTitle,
                             IDEWorkbenchMessages.ProjectCapabilityPropertyPage_invalidSelection,
                             status);
             return;
         }

         String [] natureIds = new String [1];
         natureIds[0] = cap.getNatureId();

         ICapabilityUninstallWizard wizard = cap.getUninstallWizard();
         if (wizard == null)
             wizard = new RemoveCapabilityWizard();
         if (wizard != null) {
             wizard.init(PlatformUI.getWorkbench(), StructuredSelection.EMPTY,
                     getProject(), natureIds);
             wizard.addPages();
         }

         if (wizard.getStartingPage() == null) {
             wizard.setContainer(new StubContainer());
             wizard.performFinish();
             wizard.setContainer(null);
         } else {
             wizard = cap.getUninstallWizard();
             if (wizard == null)
                 wizard = new RemoveCapabilityWizard();
             if (wizard != null)
                 wizard.init(PlatformUI.getWorkbench(),
                         StructuredSelection.EMPTY, getProject(), natureIds);
             WizardDialog dialog = new WizardDialog(getShell(), wizard);
             dialog.create();
             dialog.getShell().setSize(
                     Math
                             .max(SIZING_WIZARD_WIDTH, dialog.getShell()
                                     .getSize().x), SIZING_WIZARD_HEIGHT);
             PlatformUI.getWorkbench().getHelpSystem().setHelp(
                     dialog.getShell(),
                     IIDEHelpContextIds.UPDATE_CAPABILITY_WIZARD);
             dialog.open();
         }

         table.refresh();
     }

     /* (non-Javadoc)
      * Method declared on PreferencePage
      */
     public boolean performOk() {
         return true;
     }

     class CapabilityLabelProvider extends LabelProvider {
         private Map imageTable;

         public void dispose() {
             if (imageTable != null) {
                 Iterator it = imageTable.values().iterator();
                 while (it.hasNext())
                     ((Image) it.next()).dispose();
                 imageTable = null;
             }
         }

         public Image getImage(Object element) {
             ImageDescriptor descriptor = ((Capability) element)
                     .getIconDescriptor();
             if (descriptor == null)
                 return null;

             //obtain the cached image corresponding to the descriptor
 if (imageTable == null) {
                 imageTable = new Hashtable (40);
             }
             Image image = (Image) imageTable.get(descriptor);
             if (image == null) {
                 image = descriptor.createImage();
                 imageTable.put(descriptor, image);
             }
             return image;
         }

         public String getText(Object element) {
             Capability cap = (Capability) element;
             String text = cap.getName();
             if (isDisabledCapability(cap))
                 text = NLS.bind(IDEWorkbenchMessages.ProjectCapabilitySelectionGroup_disabledLabel, text);
             return text;
         }
     }

     class StubContainer implements IWizardContainer {
         public IWizardPage getCurrentPage() {
             return null;
         }

         public Shell getShell() {
             return ProjectCapabilityEditingPropertyPage.this.getShell();
         }

         public void showPage(IWizardPage page) {
         }

         public void updateButtons() {
         }

         public void updateMessage() {
         }

         public void updateTitleBar() {
         }

         public void updateWindowTitle() {
         }

         public void run(boolean fork, boolean cancelable,
                 IRunnableWithProgress runnable)
                 throws InvocationTargetException , InterruptedException {
             new ProgressMonitorJobsDialog(getShell()).run(fork, cancelable,
                     runnable);
         }
     }
 }

